home *** CD-ROM | disk | FTP | other *** search
- COMMENT *
-
- CLUBware (tm)
-
- ASMBASIC interfaces assembly language subroutines to the BASIC
- interpreter.
-
- Copyright 1984 Rayhawk Automation N.W. Inc
- P.O. Box 1427
- Beaverton, Oregon 97075
-
-
- Method:
- 1) Our Basic code calls the service routines directly
- CALL QPRINT ( FLAG% , STRING )
- 2) The flag indicates whether we are interpreted or compiled
- 3) Compiled code has the object code for QPRINT linked into it
- 4) Interpreted code has a separate module resident below
- the BASIC interpreter (this module contains QPRINT)
- 5) Both the interpreted Basic code and the compiled Basic code
- use an initialization routine to determine whether
- currently running compiled or interpreted and sets global
- variable, FLAG, accordingly
- 6) If compiled, basic initialization routine does nothing
- 7) If interpreted, initialization routine performs following
- steps
- A) Insert two instruction assembly language subroutine
- into variable SUBINIT
- Two instructions are INT 67h
- RET 2
- B) Make the following assignments
- SEGVALUE% = 0
- QPRINT% = 1
- ZPRINT% = 2
- CLREOL% = 3
- SHELSORT% = 4
- etc
- (Everyone concerned with this project will agree on an
- ordering and use it consistently.)
- C) Make repeated calls to SUBINIT
- CALL SUBINIT ( SEGVALUE% )
- CALL SUBINIT ( QPRINT% )
- CALL SUBINIT ( ZPRINT% )
- CALL SUBINIT ( CLREOL% )
- CALL SUBINIT ( SHELSORT% )
- D) Use the Basic DEFSEG to make our subroutines addressable
- DEFSEG = SEGVALUE%
- E) Return from initialization
- F) Implied but not stated is that after return from SUBINIT
- the variable QPRINT% no longer contains 1 but the
- offset within SEGVALUE% where the QPRINT% subroutine
- can be found. Same for other subroutines
- *
-
-
- CODE SEGMENT PARA PUBLIC 'CODE'
- ASSUME CS:CODE,DS:NOTHING,ES:NOTHING,SS:STACK
-
- ;_______________________________________________________________________________
-
-
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
- ; | |
- ; | INT 67h interrupt routine |
- ; | |
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
-
- EXTRN QPRINT:FAR
- EXTRN SCRLDN:FAR
- EXTRN SCRLUP:FAR
- EXTRN XREP:FAR
- EXTRN YREP:FAR
- EXTRN CLREOL:FAR
- EXTRN CLREOS:FAR
- EXTRN ZPRINT:FAR
- ; EXTRN STDIN:FAR
- ; EXTRN STDOUT:FAR
-
- TABLE_LEN LABEL WORD
- DW 8 ; eight subroutines so far
-
- DW 5252h ; tag to allow basic to make sure
- ; ASMBASIC is resident
- ; entry point for assembly SUBINT routine
-
- SUBINIT PROC FAR
- JMP SHORT SUB_CODE
-
- SUBROUTINE_TABLE LABEL WORD ; table of subroutine offsets
- DW OFFSET BAD_CALL ; 0
- DW OFFSET QPRINT ; 1
- DW OFFSET SCRLDN ; 2
- DW OFFSET SCRLUP ; 3
- DW OFFSET XREP ; 4
- DW OFFSET YREP ; 5
- DW OFFSET CLREOL ; 6
- DW OFFSET CLREOS ; 7
- DW OFFSET ZPRINT ; 8
- ; DW OFFSET STDIN ; 9
- ; DW OFFSET STDOUT ; 10
-
- ARG EQU WORD PTR [BP+12] ; argument to SUBINIT
-
- SUB_CODE:
-
- PUSH BP ; address the argument
- MOV BP,SP
-
- MOV SI,ARG ; load the address of the argument
- MOV AX,WORD PTR [SI] ; load the argument itself
-
-
- ; argument of 0 means return code segment for use in DEFSEG statement
-
- CMP AX,0 ; return segment?
- JA PREP_SUB
-
- MOV AX,SEG CODE ; get our segment
- MOV WORD PTR DS:[SI],AX ; return it to caller
- JMP FAR PTR SUBINIT_DONE
-
- PREP_SUB:
-
-
- ; non-zero argument means return offset of that subroutine
-
- CMP AX,TABLE_LEN
- JBE GOOD_ARGUMENT
-
- CALL FAR PTR BAD_CALL ; let user know a bad call
- MOV AX,0 ; has been made
-
- GOOD_ARGUMENT:
-
- SHL AX,1 ; each table entry is 2 bytes long
- MOV BX,AX
- MOV AX,SUBROUTINE_TABLE[BX] ; load subroutine offset
- MOV WORD PTR DS:[SI],AX ; return offset to caller
-
-
-
- ; initialization complete, return to caller
- ; stack is cleared by code within basic segment
-
- SUBINIT_DONE:
- POP BP
- IRET
-
- SUBINIT ENDP
-
- ;_______________________________________________________________________________
-
- BAD_MESSAGE LABEL BYTE
- DB 10,13,'An invalid subroutine call was made to subinit.',10,13
- DB 'There are only 8 subroutines defined within subinit.',10,13
- DB 'A request was made for a subroutine outside of this range.'
- DB 10,13,'$'
-
- BAD_CALL PROC FAR
-
- PUSH DS
-
- MOV AX,SEG CODE
- MOV DS,AX
-
- MOV DX,OFFSET BAD_MESSAGE
- MOV AH,09
- INT 21h
-
- POP DS
- RET
-
- BAD_CALL ENDP
-
- ;_______________________________________________________________________________
-
-
- ASMBASIC PROC FAR
-
- ; Establish standard DOS linkage
- PUSH DS ; Push addr of Program Segment Prefix
- XOR AX,AX ; Zero AX
- PUSH AX ; Push zero onto stack
- ; (offset of INT 20 within PSF)
-
-
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
- ; | |
- ; | take over the INT 67h |
- ; | interrupt if not already done |
- ; | |
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
-
- MOV DS,AX ; address low memory
- LDS BX,DWORD PTR DS:[019Ch] ; load interrupt vector for int 67
-
- MOV AX,WORD PTR SUBINIT
- CMP AX,WORD PTR DS:[BX]
- JNE NOT_HERE_YET
- MOV AX,WORD PTR SUBINIT+2
- CMP AX,WORD PTR DS:[BX+2]
- JNE NOT_HERE_YET
- MOV AX,WORD PTR SUBINIT+4
- CMP AX,WORD PTR DS:[BX+4]
- JNE NOT_HERE_YET
- MOV AX,WORD PTR SUBINIT+6
- CMP AX,WORD PTR DS:[BX+6]
- JNE NOT_HERE_YET
-
- JMP SHORT ALREADY_RESIDENT
-
- NOT_HERE_YET:
-
- MOV AX,SEG ASMBASIC ; Move our code segment
- MOV DS,AX ; to the data segment register
-
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
- ; | |
- ; | take over the INT 67h |
- ; | interrupt |
- ; | |
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
-
- MOV DX,OFFSET SUBINIT ; Load offset of interrupt service mod
- MOV AX,2567h ; Prepare for DOS service call type 25
- ; to establish service for INT 05
- INT 21h ; Ask DOS to establish service
-
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
- ; | |
- ; | modify INT 20 into INT 27 in the |
- ; | program segment prefix |
- ; | |
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
-
- MOV BYTE PTR ES:[01],27h ; Change INT 20h to INT 27h
-
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
- ; | |
- ; | 6) load address of ending tag into DX |
- ; | |
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
-
- MOV AX,SEG BOTSTACK
- SUB AX,SEG ASMBASIC
- MOV CL,4 ; prepare for 4 bit shift
- SHL AX,CL ; shift up (convert from seg to abs)
- ADD AX,OFFSET BOTSTACK ; add address of bottom location
- ADD AX,0103h ; Pad offset because DOS measures
- ; offset relative to Program
- ; Segment Prefix
- MOV DX,AX ; leave where DOS will find it
-
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
- ; | |
- ; | 7) use RET FAR to return to DOS and |
- ; | leave service routine resident |
- ; | |
- ; | - - - - - - - - - - - - - - - - - - - - - - - - -|
-
-
- ALREADY_RESIDENT:
-
- RET
-
- ASMBASIC ENDP
-
- CODE ENDS
-
- ;_______________________________________________________________________________
-
- STACK SEGMENT PARA STACK 'STACK'
- BOTSTACK LABEL BYTE
- DB 24 DUP('STACK***')
- TOPSTACK DB 0
- STACK ENDS
-
- END ASMBASIC